#include <iostream>
#include <string>
#include <sstream>
#include <thread>
#include <vector>

#include "zlbase/CDeviceDirector.h"
#include "zlbase/CDeviceBuilderProducer.h"

using zl::zlbase::ICommonDCBTransport;
using zl::zlbase::IBaseDatalink;
using zl::zlbase::IDoorControlBoard;

std::string convert_status(const unsigned char* buff, size_t len)
{
    std::ostringstream oss;
    for (size_t i = 0; i < len; ++i)
    {
        oss << (buff[i] == 0x00 ? "0" : "1");
    }

    return oss.str();
}

void test_door_control_board_1()
{
    std::cout << "test [ dcb@fengchao@etherudp ]: " << std::endl;

    // udp datalink, fengchao transport
    zl::zlbase::DeviceOption opt;
    opt.protocol_type = (int32_t)ICommonDCBTransport::EType::Fengchao;
    opt.linkoption.type = (int32_t)IBaseDatalink::EType::EthernetUDP;
    opt.linkoption.is_shared = false;
    opt.linkoption.localaddr = "";
    opt.linkoption.localport = 30000;
    opt.linkoption.remoteaddr = "192.168.1.11";
    opt.linkoption.remoteport = 30000;
    opt.linkoption.timeout_conn = 1000;
    opt.linkoption.timeout_read = 1000;
    opt.linkoption.timeout_write = 1000;

    zl::zlbase::CDeviceBuilderProducer producer;
    auto builder = producer.GetControlBoardBuilder();
    auto device = builder->Concreate(opt);
    device->SetCol(1);

    std::cout << "connecting to device..." << std::endl;
    auto ret = device->Connect();
    if (ret == 0)
    {
        std::cout << "connect to device failed: " << ret;
        return;
    }

    std::cout << "connect to device success, origin: "
        << device->GetTransport()->GetDatalink()->Origin() << std::endl;

    //*/
    for (int i = 1; i <= 24; ++i)
    {
        std::cout << "opening locker : " << i << std::endl;
        std::cout << "result: " << device->OpenLocker(i) << std::endl;
    }
    //*/

    /*/
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(300));

        unsigned char status1[128] = { 0x00 };
        size_t len(0);
        device->GetItemStatus(status1, len);
        std::cout << '\r';
        std::cout << "item: " << convert_status(status1, len);


        unsigned char status2[128] = { 0x00 };
        size_t len2(0);
        device->GetDoorStatus(status2, len2);
        std::cout << "\tdoor: " << convert_status(status2, len2) << std::flush;
    }
    /*/

    // close device
    std::cout << "disconnect device: " << device->Disconnect() << std::endl;
}

void test_door_control_board_2()
{
    // shared udp datalink, fengchao transport
    std::cout << "test [ dcb@fengchao@shared_etherudp ]: " << std::endl;

    // udp datalink, fengchao transport
    zl::zlbase::DeviceOption opt1, opt2, opt3;
    opt1.protocol_type = (int32_t)ICommonDCBTransport::EType::Fengchao;
    opt1.linkoption.type = (int32_t)IBaseDatalink::EType::EthernetUDP;
    opt1.linkoption.is_shared = true;
    opt1.linkoption.localaddr = "";
    opt1.linkoption.localport = 30000;
    opt1.linkoption.remoteaddr = "192.168.1.11";
    opt1.linkoption.remoteport = 30000;
    opt1.linkoption.timeout_conn = 1000;
    opt1.linkoption.timeout_read = 1000;
    opt1.linkoption.timeout_write = 1000;
    opt2 = opt1;
    opt3 = opt1;
    opt2.linkoption.remoteaddr = "192.168.1.13";
    opt3.linkoption.remoteaddr = "192.168.1.15";

    zl::zlbase::CDeviceBuilderProducer producer;
    auto builder = producer.GetControlBoardBuilder();
    auto device1 = builder->Concreate(opt1);
    device1->SetCol(1);
    auto device2 = builder->Concreate(opt2);
    device2->SetCol(3);
    auto device3 = builder->Concreate(opt3);
    device3->SetCol(5);
    std::vector<std::shared_ptr<IDoorControlBoard>> device_list{ device1, device2, device3 };

    for (auto d : device_list)
    {
        std::cout << "connecting to device: " << d->Connect() << std::endl;
        auto ret = d->Connect();
        if (ret == 0)
        {
            std::cout << "connect to device failed: " << ret;
            return;
        }

        std::cout << "connect to device success, origin: " << d->GetTransport()->GetDatalink()->Origin() << std::endl;

        //*/
        for (int i = 1; i <= 24; ++i)
        {
            std::cout << "opening locker : " << i << std::endl;
            std::cout << "result: " << d->OpenLocker(i) << std::endl;
        }


        // close device
        std::cout << "disconnect device: " << d->Disconnect() << std::endl;
    }
}

void test_door_control_board_3()
{
    std::cout << "test [ dcb@standard@serialport ]: " << std::endl;
    // serial datalink, dongcheng transport
    zl::zlbase::DeviceOption opt;
    opt.protocol_type = (int32_t)ICommonDCBTransport::EType::StandardSerial;
    opt.linkoption.type = (int32_t)IBaseDatalink::EType::SerialPort;
    opt.linkoption.is_shared = false;
    opt.linkoption.localaddr = "";
    opt.linkoption.com = "COM4";
    opt.linkoption.baud_rate = 9600;
    opt.linkoption.timeout_conn = 1000;
    opt.linkoption.timeout_read = 1000;
    opt.linkoption.timeout_write = 1000;


    zl::zlbase::CDeviceBuilderProducer producer;
    auto builder = producer.GetControlBoardBuilder();
    auto device = builder->Concreate(opt);
    device->SetCol(2);

    std::cout << "connecting to device..." << std::endl;
    auto ret = device->Connect();
    if (ret == 0)
    {
        std::cout << "connect to device failed: " << ret;
        return;
    }

    std::cout << "connect to device success, origin: "
        << device->GetTransport()->GetDatalink()->Origin() << std::endl;

    for (int i = 1; i <= 24; ++i)
    {
        std::cout << "opening locker [ " << i << " ] ";
        std::cout << "result: " << device->OpenLocker(i) << std::endl;
    }

    // close device
    std::cout << "disconnect device: " << device->Disconnect() << std::endl;
}

void test_door_control_board_4()
{
    // shared serial datalink, dongcheng transport
}

int main()
{
    std::cout << "start test door control board..." << std::endl << std::endl;

    // test_door_control_board_1();

    test_door_control_board_2();

    test_door_control_board_3();

    // test_door_control_board_4();


    system("pause");

    return 0;
}
